#include "sm2_ec.h"
#include <stdlib.h>
#include <stdio.h>
#include "sm2_operation.h"

extern const sm2_uint256_t ZERO;                // 0
extern const sm2_uint256_t ONE;                 // 1
extern const sm2_uint256_t SM2_P;               // SM2的参数p
extern const sm2_uint256_t SM2_A;               // SM2的参数a
extern const sm2_uint256_t SM2_B;               // SM2的参数b
extern const sm2_uint256_t SM2_N;               // SM2的参数n
extern const sm2_uint512_t SM2_Ps[13];          // 快速模P乘法运算优化相关，存储1P到13P的结果
extern const sm2_uint512_t SM2_P_sqr;           // 快速模P乘法运算优化相关，存储P^2的结果
extern const sm2_uint256_t Gx;                  // SM2的基点G的x坐标
extern const sm2_uint256_t Gy;                  // SM2的基点G的y坐标
extern const sm2_uint256_t SM2_N_MINUS_ONE;     // SM2的参数n-1

// G点
const SM2_Jacobian_Point SM2_G = 
{
     .x = {0x334C74C7, 0x715A4589, 0xF2660BE1, 0x8FE30BBF, 0x6A39C994, 0x5F990446, 0x1F198119, 0x32C4AE2C},
     .y = {0x2139F0A0, 0x02DF32E5, 0xC62A4740, 0xD0A9877C, 0x6B692153, 0x59BDCEE3, 0xF4F6779C, 0xBC3736A2},
     .z = {1}
};

/**
 * @brief   设置Jacobian加重射影坐标系点位无穷远点 => (1, 1, 0)
 * 
 * @details Jacobian加重射影坐标系的点包含（X，Y，Z），其中无穷远点表示为 (1, 1, 0)
 * 
 * @param[in, out] p 传入Jacobian点类型，对其进行赋值
 * 
 * @return 无返回值
 * 
 * @note 无
 * @pre  无
 * @post 无
 */
void sm2_set_point_infi(SM2_Jacobian_Point *p) 
{
    sm2_set_one(p->x); 
    sm2_set_one(p->y); 
    sm2_set_zero(p->z); 
}

/**
 * @brief   将仿射坐标转换为Jacobian坐标。
 * 
 * @details 该函数将输入的仿射坐标 (x, y) 转换为Jacobian坐标 (X, Y, Z)，其中 X 和 Y 分别为输入的 x 和 y，Z 设置为 1，表示标准化的Jacobian坐标。
 * 
 * @param[out] result   指向 `SM2_Jacobian_Point` 结构体的指针，表示转换后的Jacobian坐标。
 * @param[in]  x        输入的仿射坐标 x。
 * @param[in]  y        输入的仿射坐标 y。
 * 
 * @return 无返回值
 * 
 * @note    `result` 应为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `result` 是有效的 `SM2_Jacobian_Point` 指针，且其结构体成员 `x`, `y`, `z` 为有效数值。
 * @post    `result->x` 和 `result->y` 将被设置为输入的 `x` 和 `y`，`result->z` 将被设置为 1，表示标准化的Jacobian坐标。
 */
void sm2_set_jacobian_point(SM2_Jacobian_Point *result, const sm2_uint256_t x, const sm2_uint256_t y)
{
    sm2_copy(result->x, x);
    sm2_copy(result->y, y);
    sm2_set_one(result->z);
}

/**
 * @brief   将仿射坐标点转换为Jacobian坐标。(以仿射坐标类型作为输入)
 * 
 * @details 该函数将输入的标准坐标点 `a` 转换为Jacobian坐标点，设置其 `x` 和 `y` 为输入点 `a` 的坐标，`z` 设置为 1，表示标准化的Jacobian坐标。
 * 
 * @param[out] result   指向 `SM2_Jacobian_Point` 结构体的指针，表示转换后的Jacobian坐标。
 * @param[in]  a        输入的标准坐标点，类型为 `SM2_Point`。
 * 
 * @return 无返回值
 * 
 * @note    `result` 应为有效的 `SM2_Jacobian_Point` 结构体指针，`a` 应为有效的 `SM2_Point` 结构体。
 * @pre     `result` 是有效的 `SM2_Jacobian_Point` 指针，且其结构体成员 `x`, `y`, `z` 为有效数值；`a` 是有效的 `SM2_Point` 结构体。
 * @post    `result->x` 和 `result->y` 将被设置为输入的 `a->x` 和 `a->y`，`result->z` 将被设置为 1，表示标准化的Jacobian坐标。
 */
void sm2_set_jacobian_point_from_std(SM2_Jacobian_Point *result, const SM2_Point *a)
{
    sm2_copy(result->x, a->x);
    sm2_copy(result->y, a->y);
    sm2_set_one(result->z);
}


/**
 * @brief   从Jacobian坐标转换为标准坐标。
 * 
 * @details 该函数将输入的Jacobian坐标点 `p` 转换为标准坐标点，并将其 `x` 和 `y` 坐标存储到 `result` 中。
 *          先通过 `sm2_get_affine_point` 获取仿射坐标，再将仿射坐标的 `x` 和 `y` 赋值给标准坐标点 `result`。
 * 
 * @param[out] result   指向 `SM2_Point` 结构体的指针，用于存储转换后的标准坐标点。
 * @param[in]  p        指向 `SM2_Jacobian_Point` 结构体的指针，表示输入的Jacobian坐标点。
 * 
 * @return 无返回值
 * 
 * @note    `result` 和 `p` 应为有效的 `SM2_Point` 和 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `result` 是有效的 `SM2_Point` 指针，且 `p` 是有效的 `SM2_Jacobian_Point` 指针。
 * @post    `result->x` 和 `result->y` 将被设置为通过 `sm2_get_affine_point` 得到的 `tmp.x` 和 `tmp.y`，表示标准坐标。
 */
void sm2_get_std_point(SM2_Point *result, const SM2_Jacobian_Point *p)
{
    SM2_Jacobian_Point tmp;
    sm2_get_affine_point(&tmp, p);
    sm2_copy(result->x, tmp.x);
    sm2_copy(result->y, tmp.y);
}

/**
 * @brief   将Jacobian坐标转换为仿射坐标。
 * 
 * @details 该函数将Jacobian坐标点 `p` 转换为仿射坐标，并将转换后的坐标存储到 `result` 中。 
 *          如果 `p` 的 `z` 坐标为零，表示无穷远点，函数会直接将 `p` 复制到 `result`。 
 *          否则，通过计算 `z^2` 和 `z^3` 的逆元来转换坐标，最后更新 `result` 的 `x` 和 `y` 坐标。
 * 
 * @param[out] result   指向 `SM2_Jacobian_Point` 结构体的指针，用于存储转换后的仿射坐标点。
 * @param[in]  p        指向 `SM2_Jacobian_Point` 结构体的指针，表示输入的Jacobian坐标点。
 * 
 * @return 无返回值
 * 
 * @note    `result` 和 `p` 应为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `result` 是有效的 `SM2_Jacobian_Point` 指针，且 `p` 是有效的 `SM2_Jacobian_Point` 指针。
 * @post    `result->x` 和 `result->y` 将被更新为对应的仿射坐标，`result->z` 被设置为 1。
 */
void sm2_get_affine_point(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p)
{
    // 将Jacobian坐标转换为仿射坐标 -----------有疑问?
    // Z == 1
    if(sm2_compare(p->z, ZERO) == SM2_COMPARE_EQ){ // 修复无穷远点的bug
        sm2_point_copy(result, p);
        return;
    }
    sm2_set_one(result->z);
    if(p->z[0] == 1){
        // printf("here 1\n");
        sm2_copy(result->x, p->x);
        sm2_copy(result->y, p->y);
    }else{
        // 计算Z^2, Z^3的逆元
        // ?求平方逆元是否需要mod p转化为256bit再进行求逆元
        sm2_uint256_t temp_1={0}, temp_2={0};
        sm2_mod_sqr(temp_1, p->z);
        sm2_fast_mod_inverse(temp_2, temp_1);
        sm2_mod_mul(result->x, p->x, temp_2);

        sm2_mod_mul(temp_2, temp_1, p->z);
        sm2_fast_mod_inverse(temp_1, temp_2); // temp3 = 1 / Z^3
        sm2_mod_mul(result->y, p->y, temp_1); // y = Y / Z^3
    }
}

/**
 * @brief   比较两个Jacobian坐标点是否相等。
 * 
 * @details 该函数将输入的两个Jacobian坐标点 `a` 和 `b` 转换为仿射坐标，然后比较它们的 `x` 和 `y` 坐标是否相等。如果两者的 `x` 和 `y` 坐标相等，返回 1，表示两个点相等；否则返回 0，表示不相等。
 * 
 * @param[in] a    指向第一个 `SM2_Jacobian_Point` 结构体的指针，表示第一个坐标点。
 * @param[in] b    指向第二个 `SM2_Jacobian_Point` 结构体的指针，表示第二个坐标点。
 * 
 * @return 如果 `a` 和 `b` 相等，则返回 1；否则返回 0。
 * 
 * @note    `a` 和 `b` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `a` 和 `b` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    无。
 */
int sm2_point_compare(const SM2_Jacobian_Point *a, const SM2_Jacobian_Point *b)
{
    SM2_Jacobian_Point t1, t2;
    sm2_get_affine_point(&t1, a);
    sm2_get_affine_point(&t2, b);
    if(sm2_compare(t1.x, t2.x) == SM2_COMPARE_EQ && \
    sm2_compare(t1.y, t2.y) == SM2_COMPARE_EQ) return 1;

    return 0;
}

/**
 * @brief   复制一个Jacobian坐标点到另一个Jacobian坐标点。
 * 
 * @details 该函数将输入的Jacobian坐标点 `p` 的 `x`、`y` 和 `z` 坐标复制到目标坐标点 `result`。
 * 
 * @param[out] result   指向目标 `SM2_Jacobian_Point` 结构体的指针，用于存储复制结果。
 * @param[in]  p        指向源 `SM2_Jacobian_Point` 结构体的指针，表示要复制的坐标点。
 * 
 * @return 无。
 * 
 * @note    `result` 和 `p` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `result` 和 `p` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    `result` 的 `x`、`y` 和 `z` 坐标被复制为 `p` 的坐标。
 */
void sm2_point_copy(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p)
{
    sm2_copy(result->x, p->x);
    sm2_copy(result->y, p->y);
    sm2_copy(result->z, p->z);
}

/**
 * @brief   检查两个Jacobian坐标点是否互为逆点。
 * 
 * @details 该函数判断两个Jacobian坐标点 `p1` 和 `p2` 是否互为逆点。对于椭圆曲线上的点 `P`，其逆点是指点 `-P`，满足 `P + (-P) = O`（即无穷远点）。
 * 
 * @param[in]  p1   指向第一个 `SM2_Jacobian_Point` 结构体的指针，表示第一个坐标点。
 * @param[in]  p2   指向第二个 `SM2_Jacobian_Point` 结构体的指针，表示第二个坐标点。
 * 
 * @return 如果 `p1` 和 `p2` 是互为逆点，返回 1；否则返回 0。
 * 
 * @note    `p1` 和 `p2` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `p1` 和 `p2` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    如果 `p1` 和 `p2` 是互为逆点，函数返回 1；否则返回 0。
 */
int sm2_is_point_inverse(const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2)
{
    sm2_uint256_t result;
    sm2_uint256_t zero;
    sm2_set_zero(zero);

    if(sm2_compare(p1->x, p2->x) == SM2_COMPARE_EQ && sm2_compare(p1->z, p2->z) == SM2_COMPARE_EQ) {
        sm2_mod_add(result, p1->y, p2->y);
        if(sm2_compare(zero, result) == SM2_COMPARE_EQ) {
            return 1;
        }
    }
    return 0;
}

/**
 * @brief   检查两个Jacobian坐标点是否相等。
 * 
 * @details 该函数通过比较两个Jacobian坐标点 `p1` 和 `p2` 的坐标来判断它们是否相等。具体做法是：
 *          1. 计算 `X1 * Z2^2 == X2 * Z1^2`，若不相等，则返回 0。
 *          2. 计算 `Y1 * Z2^3 == Y2 * Z1^3`，若不相等，则返回 0。
 *          3. 若两者相等，则返回 1。
 * 
 * @param[in]  p1   指向第一个 `SM2_Jacobian_Point` 结构体的指针，表示第一个坐标点。
 * @param[in]  p2   指向第二个 `SM2_Jacobian_Point` 结构体的指针，表示第二个坐标点。
 * 
 * @return 如果 `p1` 和 `p2` 相等，返回 1；否则返回 0。
 * 
 * @note    `p1` 和 `p2` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `p1` 和 `p2` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    如果 `p1` 和 `p2` 相等，函数返回 1；否则返回 0。
 */
int sm2_jacobian_point_equal(const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2)
{
	sm2_uint256_t Z1, Z2, V1, V2;

	// X1 * Z2^2 == X2 * Z1^2
    sm2_mod_sqr(Z1, p1->z);
    sm2_mod_sqr(Z2, p2->z);
    sm2_mod_mul(V1, p1->x, Z2);
    sm2_mod_mul(V2, p2->x, Z1);
	if (sm2_compare(V1, V2) != SM2_COMPARE_EQ) {
		return 0;
	}

	// Y1 * Z2^3 == Y2 * Z1^3
	sm2_mod_mul(Z1, Z1, p1->z);
	sm2_mod_mul(Z2, Z2, p2->z);
	sm2_mod_mul(V1, p1->y, Z2);
	sm2_mod_mul(V2, p2->y, Z1);
	if (sm2_compare(V1, V2) != SM2_COMPARE_EQ) {
		return 0;
	}

	return 1;
}

/**
 * @brief   对给定的Jacobian坐标点进行倍点操作。
 * 
 * @details 该函数通过将点 `a` 与自身相加来计算其倍点，即 `result = a + a`。实际上，调用了 `sm2_jacobian_point_add` 函数来执行加法操作。
 * 
 * @param[out]  result   指向 `SM2_Jacobian_Point` 结构体的指针，表示存储结果的坐标点。
 * @param[in]   a        指向 `SM2_Jacobian_Point` 结构体的指针，表示需要进行倍点运算的坐标点。
 * 
 * @note    `a` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `a` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    如果操作成功，`result` 将存储 `a + a` 的倍点结果。
 */
void sm2_point_double(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *a)
{
    sm2_jacobian_point_add(result, a, a);
}


/**
 * @brief   执行Jacobian坐标系中的椭圆曲线点加法操作。
 * 
 * @details 该函数实现了椭圆曲线的加法运算。首先，通过处理特殊情况（如无穷远点、零点等）来判断 `p1` 和 `p2` 是否为无穷远点或是否相等。如果两个点是相反点，则结果为无穷远点。如果两个点相等，则使用倍点公式。对于一般情况，使用Jacobian坐标系中的标准加法公式进行点加法运算。
 * 
 * @param[out]  result   指向 `SM2_Jacobian_Point` 结构体的指针，表示存储加法结果的坐标点。
 * @param[in]   p1       指向 `SM2_Jacobian_Point` 结构体的指针，第一个加法点。
 * @param[in]   p2       指向 `SM2_Jacobian_Point` 结构体的指针，第二个加法点。
 * 
 * @note    `p1` 和 `p2` 必须为有效的 `SM2_Jacobian_Point` 结构体指针。
 * @pre     `p1` 和 `p2` 是有效的 `SM2_Jacobian_Point` 结构体指针。
 * @post    如果加法操作成功，`result` 将存储加法结果，即 `p1 + p2`。
 * 
 * @details
 * 1. 处理特殊情况：如果 `p1` 或 `p2` 是无穷远点，则直接将结果设置为另一个点。
 * 2. 如果 `p1` 和 `p2` 是相反点，则将结果设置为无穷远点。
 * 3. 如果 `p1` 和 `p2` 相等，则使用倍点公式来计算加法结果。
 * 4. 对于一般情况，使用标准的Jacobian加法公式来计算 `p1 + p2`。
 * 
 * 计算的步骤包括：
 * - 计算各项临时值（如 `l_1`, `l_2`, `l_3` 等）。
 * - 更新 `result->x`, `result->y`, `result->z` 来得到加法结果。
 */
void sm2_jacobian_point_add(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2)
{
    sm2_uint256_t zero;
    sm2_set_zero(zero);

    if(sm2_compare(p1->z, zero) == SM2_COMPARE_EQ && \
    sm2_compare(p2->z, zero) == SM2_COMPARE_EQ) {
        sm2_set_point_infi(result);
        return;
    }

    if(sm2_compare(p1->z, zero) == SM2_COMPARE_EQ) {
        sm2_point_copy(result, p2);
        return;
    }

    if(sm2_compare(p2->z, zero) == SM2_COMPARE_EQ) {
        sm2_point_copy(result, p1);
        return;
    }

    if(sm2_is_point_inverse(p1, p2)) {
        printf("p1 == -p2\n");
        sm2_set_point_infi(result);
        return;
    }

    sm2_uint256_t l_1={0}, l_2={0}, l_3={0};
    sm2_uint256_t temp_1, temp_2, temp_3, temp_4;
    sm2_uint256_t x1_sqr = {0}, y1_sqr = {0}, z1_sqr = {0};
    
    // 没问题
    sm2_mod_sqr(x1_sqr, p1->x);
    sm2_mod_sqr(z1_sqr, p1->z);
    sm2_mod_sqr(y1_sqr, p1->y);

    if(sm2_jacobian_point_equal(p1, p2))  {
        // printf("p1 == p2\n");
        
        // sm2_k_mul(temp_2, 3, x1_sqr);
        // sm2_fast_mod_reduction(temp_4, temp_2); // temp_4 = 3*x^2
        sm2_mod_k_mul(temp_4, 3, x1_sqr);
        // sm2_sqr(temp_1, z1_sqr);
        // sm2_fast_mod_reduction(temp_3, temp_1); // temp_3 = z1^4
        sm2_mod_sqr(temp_3, z1_sqr);
        // sm2_mul(temp_1, SM2_A, temp_3); //temp_1 = a*z1^4
        sm2_mod_mul(temp_1, SM2_A, temp_3);
        // sm2_add(temp_3, temp_4, temp_1); //temp_3 = 3x1^2 + az1^4
        // sm2_fast_mod_reduction(l_1, temp_3); //l_1 finished
        sm2_mod_add(l_1, temp_4, temp_1);

        // sm2_k_mul(temp_2, 4, p1->x);
        // sm2_fast_mod_reduction(temp_1, temp_2); // temp1 = 4^x1
        sm2_mod_k_mul(temp_1, 4, p1->x);
        // sm2_mul(temp_2, y1_sqr, temp_1);
        // sm2_fast_mod_reduction(l_2, temp_2); // l_2 = 4*x1*y1^2
        sm2_mod_mul(l_2, y1_sqr, temp_1);
        // sm2_sqr(temp_1, y1_sqr); 
        // sm2_fast_mod_reduction(temp_2, temp_1); // temp_2 = y1^4
        sm2_mod_sqr(temp_2, y1_sqr);
        // sm2_k_mul(temp_1, 8, temp_2); // temp_1 = 8*y1^4
        // sm2_fast_mod_reduction(l_3, temp_1); // l_3 finished
        sm2_mod_k_mul(l_3, 8, temp_2);

        // sm2_sqr(temp_1, l_1);
        // sm2_fast_mod_reduction(temp_2, temp_1); // temp_2 = l_1^2
        sm2_mod_sqr(temp_2, l_1);

        // sm2_k_mul(temp_1, 2, l_2);
        // sm2_fast_mod_reduction(temp_3, temp_1); // temp_3 = 2*l_2
        sm2_mod_k_mul(temp_3, 2, l_2);
        // sm2_sub(temp_1, temp_2, temp_3);
        // sm2_fast_mod_reduction(result->x, temp_1); // x3 finished
        sm2_mod_sub(result->x, temp_2, temp_3);
        
        // sm2_sub(temp_1, l_2, result->x);
        // sm2_fast_mod_reduction(temp_2, temp_1);
        sm2_mod_sub(temp_2, l_2, result->x);
        // sm2_mul(temp_1, l_1, temp_2);
        // sm2_fast_mod_reduction(temp_3, temp_1); // temp_3 = l_1(l_2-x3)
        sm2_mod_mul(temp_3, l_1, temp_2);

        // sm2_sub(temp_1, temp_3, l_3);
        // sm2_fast_mod_reduction(result->y, temp_1);
        sm2_mod_sub(result->y, temp_3, l_3);

        // sm2_k_mul(temp_1, 2, p1->y);
        // sm2_fast_mod_reduction(temp_2, temp_1); // temp_2 = 2*y1
        sm2_mod_k_mul(temp_2, 2, p1->y);

        // sm2_mul(temp_1, temp_2, p1->z);
        // sm2_fast_mod_reduction(result->z, temp_1); // z3 = 2*y1*z1
        sm2_mod_mul(result->z, temp_2, p1->z);
    } else {
        // printf("p1 != p2\n");
        sm2_uint256_t l_4={0}, l_5={0}, l_6={0}, l_7={0}, l_8={0};
        sm2_uint256_t z2_sqr={0};

        // sm2_sqr(temp_1, p2->z); 
        // sm2_fast_mod_reduction(z2_sqr, temp_1); // z2_sqr = z2^2
        sm2_mod_sqr(z2_sqr, p2->z);

        // sm2_mul(temp_1, p1->x, z2_sqr);
        // sm2_fast_mod_reduction(l_1, temp_1); // l_1 = x1*z2^2
        sm2_mod_mul(l_1, p1->x, z2_sqr);

        // sm2_mul(temp_1, p2->x, z1_sqr);
        // sm2_fast_mod_reduction(l_2, temp_1); // l_2 = x2*z1^2
        sm2_mod_mul(l_2, p2->x, z1_sqr);
        sm2_mod_sub(l_3, l_1, l_2); // l3 = l1 - l2

        // sm2_mul(temp_1, p2->z, z2_sqr);
        // sm2_fast_mod_reduction(tmp1, temp_1); // temp_2 = z2^3
        sm2_mod_mul(temp_2, p2->z, z2_sqr);
        // sm2_mul(temp_1, p1->y, tmp1);
        // sm2_fast_mod_reduction(l_4, temp_1); // l_4 = y1 * z2^3
        sm2_mod_mul(l_4, p1->y, temp_2);

        // sm2_mul(temp_1, p1->z, z1_sqr);
        // sm2_fast_mod_reduction(tmp1, temp_1); // temp_2 = z1^3
        sm2_mod_mul(temp_2, p1->z, z1_sqr);
        // sm2_mul(temp_1, p2->y, tmp1);
        // sm2_fast_mod_reduction(l_5, temp_1); // l_5 = y2 * z1^3
        sm2_mod_mul(l_5, p2->y, temp_2);
        sm2_mod_sub(l_6, l_4, l_5); // l6 = l4 - l5

        // c = sm2_add(tmp1, l_1, l_2);
        // sm2_set_512_zero(temp_1);
        // for(int i=0; i<8;i++){
        //     temp_1[i] = tmp1[i];
        // }
        // temp_1[8] = c;
        // printf("add c = %d\n", c);
        // sm2_fast_mod_reduction(l_7, temp_1); // l_7 = l_1 + l_2
        sm2_mod_add(l_7, l_1, l_2);
        // c = sm2_add(tmp1, l_4, l_5);
        // sm2_set_512_zero(temp_1);
        // for(int i=0; i<8;i++){
        //     temp_1[i] = tmp1[i];
        // }
        // temp_1[8] = c;
        // printf("add c = %d\n", c);
        // sm2_fast_mod_reduction(l_8, temp_1); // l_8 = l_4 + l_5
        sm2_mod_add(l_8, l_4, l_5);

        // sm2_sqr(temp_1, l_6); 
        // sm2_fast_mod_reduction(tmp1, temp_1); // temp_2 = l_6 ^ 2 -> tmp1
        sm2_mod_sqr(temp_2, l_6);
        // sm2_sqr(temp_1, l_3); 
        // sm2_fast_mod_reduction(tmp2, temp_1); // temp_3 = l_3^2 -> tmp2
        sm2_mod_sqr(temp_3, l_3);
        // sm2_mul(temp_4, l_7, tmp2);
        // sm2_fast_mod_reduction(tmp3, temp_4); // temp_1 = l_7 * l_3^2 -> tmp3
        sm2_mod_mul(temp_1, l_7, temp_3);
        // sm2_set_512_zero(temp_3);
        
        sm2_mod_sub(result->x, temp_2, temp_1); // x3 = λ_6 ^ 2  - λ_7 * λ_3 ^ 2   
        // for(int i=0; i<8;i++){
        //     temp_3[i] = tmp2[i];
        // }
        // // _print_512(temp_3);
        // sm2_fast_mod_reduction(result->x, temp_3); // x3 = ...
        // printf("temp3\n");
        // _print_512(temp_3);
        // printf("result->x\n");
        // _print_256(result->x);

        // sm2_sqr(temp_1, l_3);
        // sm2_fast_mod_reduction(tmp2, temp_1); // temp_2 = l_3^2 -> tmp2
        sm2_mod_sqr(temp_2, l_3);
        // sm2_mul(temp_1, l_1, tmp2); 
        // sm2_fast_mod_reduction(tmp3, temp_1); // temp_3 = l_1 * l_3^2 -> tmp3
        sm2_mod_mul(temp_3, l_1, temp_2);
        sm2_mod_sub(temp_1, temp_3, result->x);
        // sm2_fast_mod_reduction(temp_2, tmp1); // temp_2 = l_1* l_3^2 - l_3^2
        // sm2_mul(temp_1, tmp1, l_6);
        // sm2_fast_mod_reduction(tmp2, temp_1); // temp_2 = l_6 * (l_1 * l_3^2 - x3) ->tmp2
        sm2_mod_mul(temp_2, temp_1, l_6);

        // sm2_sqr(temp_1, l_3);
        // sm2_fast_mod_reduction(tmp3, temp_1); // temp_3 = l_3^2
        sm2_mod_sqr(temp_3, l_3);
        // sm2_mul(temp_4, l_3, tmp3);
        // sm2_fast_mod_reduction(tmp1, temp_4); // temp_1 = l_3^3
        sm2_mod_mul(temp_1, l_3, temp_3);
        // sm2_mul(temp_1, l_4, tmp1);
        // sm2_fast_mod_reduction(tmp3, temp_1); // temp_3 = l_4 * l_3^3 ->tmp3
        sm2_mod_mul(temp_3, l_4, temp_1);
        sm2_mod_sub(result->y, temp_2, temp_3);
        // sm2_fast_mod_reduction(result->y, temp_1); // y3 = ...

        // sm2_mul(temp_1, p1->z, p2->z);
        // sm2_fast_mod_reduction(tmp2, temp_1);
        sm2_mod_mul(temp_2, p1->z, p2->z);
        // sm2_mul(temp_1, tmp2, l_3);
        // sm2_fast_mod_reduction(result->z, temp_1); // z3 = ...
        sm2_mod_mul(result->z, temp_2, l_3);
    }
}


// #define R 5
// SM2_Jacobian_Point Gs[31];


void printBinary(uint32_t n) {
    if (n == 0)
        return;
 
    printBinary(n / 2);
    printf("%d", n % 2);
}

void sm2_jacobian_point_k_mul(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *a, const sm2_uint256_t k)
{   
    // 预计算
    SM2_Jacobian_Point Ps[31];

    // step a
    sm2_point_copy(&Ps[0], a);
    sm2_jacobian_point_add(&Ps[1], a, a);
    
    // step b
    for(int i = 0; i < 15; ++i){

        sm2_jacobian_point_add(&Ps[2*i+2], &Ps[2*i], &Ps[1]);
    }

    // step c
    SM2_Jacobian_Point Q, temp;
    sm2_set_point_infi(&Q);

    // step d
    uint32_t idx, m, j = 255; // idx表示第idx个块, m表示在该块下的相对位置(从右往左), j表示256bit的第j个全局位置
    idx = j >> 5;
    m = j << 27 >> 27;
    uint32_t t = 0, T, T_l, c;
    // sm2_uint256_t h_j={0};
    uint32_t h_j = 0;
    while(!(j & (uint32_t)1 << 31)){
        // printf("j=%d,idx=%d,m=%d\n", j, idx, m);
        // printBinary(k[idx]);
        if((k[idx] >> m) & (uint32_t)1){
            // printf("\nif j = %d\n", j);
            // d.2.1
            t = j - 4;
            if(t >= 256){
                t = 0;
            }
            T = t >> 5; // 获取t这个位置在哪个块
            T_l = t << 27 >> 27; // 获取t的位置 在 块中的位置(从右往左数)
            // 循环获取该位置的bit值，并判断是1还是0
            while(((k[T] >> T_l) & (uint32_t)1) == 0){
                T_l++;
                t++;
                if(T_l == 32){
                    T++;
                    // if(T > 8){ //一定能找到1
                    //     break;
                    // }
                    T_l = 0;
                }
            }
            // printf("t = %d\n", t);
            // d.2.2
            // sm2_set_zero(h_j);
            h_j = 0;
            if(T == idx){ // t和j在同一个块
                h_j = k[idx] << (31 - m) >> (31 - m + T_l);
            }else{ // j > t并且不在同一个块
                h_j = k[T] >> T_l;
                h_j |= k[idx] << (31 - m) >> (T_l - m - 1);
            }
            // printf("h_j=%d\n", h_j);
            // d.2.3
            for(c = 0; c < j-t+1; ++c){
                sm2_jacobian_point_add(&temp, &Q, &Q);
                sm2_point_copy(&Q, &temp);
            }
            sm2_jacobian_point_add(&temp, &Q, &Ps[h_j-1]);
            sm2_point_copy(&Q, &temp);
            // print_point(&Q);
            // print_point(&Ps[0]);
            j = t - 1;

        }else{ // kj=0
            sm2_point_copy(&temp, &Q);
            sm2_jacobian_point_add(&Q, &temp, &temp);
            // sm2_get_affine_point(&temp, &Q);
            // print_point(&temp);
            // printf("\nelse j = %d\n", j);
            j--;
        }
        // 计算新的块以及相对位置
        idx = j >> 5;
        m = j << 27 >> 27;
    }
    sm2_point_copy(result, &Q);
}

/**
 * @brief   检查SM2椭圆曲线上的点是否满足曲线方程
 * 
 * @details 此函数验证给定的SM2雅可比坐标点是否位于SM2椭圆曲线方程上。 
 *          通过计算椭圆曲线方程的左右两边，若两者相等，则该点满足曲线方程。
 * 
 * @param[in]  a  指向SM2雅可比坐标点的指针。该点是要检查是否在曲线上的点。
 * 
 * @return 返回值：
 *         - 0：点不在椭圆曲线方程上。
 *         - 1：点在椭圆曲线方程上。
 * 
 * @note    函数使用了SM2算法中定义的常量SM2_A和SM2_B来进行计算。
 * @warning 如果输入的点坐标无效或未初始化，可能导致计算错误。
 * @pre     输入参数`a`必须是有效的SM2雅可比坐标点。
 * @post    若函数返回1，表示输入点确实在曲线方程上；若返回0，表示输入点不在曲线方程上。
 */
int sm2_point_on_curve(const SM2_Jacobian_Point *a)
{
    SM2_Jacobian_Point tmp;
    sm2_get_affine_point(&tmp, a);
    sm2_uint256_t x_3={0}, temp, a_x, y_2, res;
    sm2_mod_sqr(temp, a->x);
    sm2_mod_mul(x_3, temp, a->x); // x_3 = x^3
    sm2_mod_mul(a_x, SM2_A, a->x);
    sm2_mod_add(temp, x_3, a_x);
    sm2_mod_add(res, temp, SM2_B);
    sm2_mod_sqr(y_2, a->y);
    return sm2_compare(res, y_2);
}

/**
 * @brief   打印SM2雅可比坐标点的值
 * 
 * @details 此函数用于打印SM2雅可比坐标点`p`的x、y、z坐标值。如果传入的指针`p`为空，函数会打印"NULL"以指示无效输入。
 * 
 * @param[in]  p  指向SM2雅可比坐标点的指针，该点包含x、y、z坐标信息。
 * 
 * @return 无返回值。
 * 
 * @note    该函数使用了 `_print_256` 来打印每个坐标值，假设 `_print_256` 是打印256位整数的辅助函数。
 * @warning 如果输入的`p`为空指针，函数会打印"NULL"，但不会执行进一步的打印操作。
 * @pre     输入参数`p`可以是有效的SM2雅可比坐标点，或为空指针。
 * @post    无论是否为空指针，函数执行后都会输出点的坐标（若有效）或"NULL"。
 */
void print_point(const SM2_Jacobian_Point *p)
{
    if(!p){
        printf("NULL\n");
        return;
    }
    printf("Point(\n");
    print_256(p->x);
    print_256(p->y);
    print_256(p->z);
    printf(")\n");
}

#define POINT_ADD 1
#define POINT_SUB 2
#define POINT_K_MUL 3
#define POINT_IS_ON_CURVE 4
void test_point_operation(int op, SM2_Jacobian_Point *true_answer, SM2_Jacobian_Point *a, SM2_Jacobian_Point *b, sm2_uint256_t k)
{
    SM2_Jacobian_Point tmp = {0};
    int res = 0;
    if(op == POINT_ADD){
        printf("Point Oeration: Point ADD\n");
        sm2_jacobian_point_add(&tmp, a, b);
        int x = sm2_jacobian_point_equal(true_answer, &tmp);
        // if(x){
        //     printf("equal !!!!!!!!!!!!!!!!!!!\n");
        // }
        res = sm2_point_compare(true_answer, &tmp);
    }else if(op == POINT_K_MUL){
        printf("Point Oeration: Point K-MUL\n");
        sm2_jacobian_point_k_mul(&tmp, a, k);
        res = sm2_point_compare(true_answer, &tmp);
    }else if(op == POINT_IS_ON_CURVE){
        printf("Point Oeration: Point Is-On-Curve\n");
        res = sm2_point_on_curve(a);
    }
    if(res == 1){
        printf("correct answer!\n");
    }else{
        printf("wrong answer!\n");
    }
    printf("your result is\n");
    SM2_Jacobian_Point tmp1;
    sm2_get_affine_point(&tmp1, &tmp);
    print_point(&tmp1);
    printf("true answer is\n");
    print_point(true_answer);
    printf("\n");
}

#define Z256_ADD 1
#define Z256_SUB 2
#define Z256_NEG 3
#define Z256_MOD 4
#define Z256_INV 5
void test_z256_operation(int op, sm2_uint256_t true_answer, sm2_uint256_t a, sm2_uint256_t b)
{
    int res;
    sm2_uint256_t tmp={0};
    if(op == Z256_ADD){
        printf("Number Oeration: ADD\n");
        sm2_mod_add(tmp, a, b);
    }else if(op == Z256_SUB){
        printf("Number Oeration: SUB\n");
        sm2_mod_sub(tmp, a, b);
    }else if(op == Z256_NEG){
        printf("Number Oeration: NEG\n");
        sm2_mod_neg(tmp, a);
    }else if(op == Z256_MOD){
        printf("Number Oeration: MOD\n");
        sm2_uint512_t aa = {0};
        sm2_copy(aa, a);
        sm2_fast_mod_reduction(tmp, aa);
    }else if(op == Z256_INV){
        printf("Number Oeration: INV\n");
        sm2_fast_mod_inverse(tmp, a);
    }
    res = sm2_compare(true_answer, tmp);
    if(res == 1){
        printf("correct answer!\n");
    }else{
        printf("wrong answer!\n");
    }
    printf("your result is\n");
    print_256(tmp);
    printf("true answer is\n");
    print_256(true_answer);
    printf("\n");
}

// int main(void)
// {
//     // printf("hello world\n");
//     // sm2_uint256_t x1 = {0x700dcbf6, 0x87a68461, 0xdb3d92fe, 0x194a4832, 0x5f3cfcb1, 0xf7a57dae, 0xc65dc547, 0xbf3402f8};
//     // sm2_uint256_t y1 = {0xc78387ed, 0xd524bcf0, 0x0fbb123f, 0x48b12505, 0x47f8bc7b, 0x74f5cdcc, 0x7b49bb6f, 0xcead1358};
    
//     // sm2_uint256_t x2 = {0xf05fc1b3, 0xb9b33a69, 0x9fc2f9db, 0x525230a0, 0x92afb669, 0x2d7f59d2, 0xcce04c9d, 0x1e910287};
//     // sm2_uint256_t y2 = {0x7956656b, 0x481ef69a, 0x783cb3de, 0xd8822204, 0xde7a254e, 0xcbbe9bd2, 0x7b1e05e3, 0x533984fb};

//     // sm2_uint256_t Gx = {0x334C74C7, 0x715A4589, 0xF2660BE1, 0x8FE30BBF, 0x6A39C994, 0x5F990446, 0x1F198119, 0x32C4AE2C};
//     // sm2_uint256_t Gy = {0x2139F0A0, 0x02DF32E5, 0xC62A4740, 0xD0A9877C, 0x6B692153, 0x59BDCEE3, 0xF4F6779C, 0xBC3736A2};

//     // SM2_Jacobian_Point p1, p2, p3, G;
//     // //memset(&p1, 0, sizeof(SM2_Jacobian_Point));
//     // //memset(&p2, 0, sizeof(SM2_Jacobian_Point));
//     // //memset(&p3, 0, sizeof(SM2_Jacobian_Point));
//     // sm2_copy(p1.x, x1);
//     // sm2_copy(p1.y, y1);
//     // sm2_copy(G.x, Gx);
//     // sm2_copy(G.y, Gy);
//     // sm2_copy(p2.x, x2);
//     // sm2_copy(p2.y, y2);
//     // p1.z[0] = 1;
//     // p2.z[0] = 1;
//     // G.z[0] = 1;

//     // 没通过，测试用例估计有问题 
//     // sm2_uint256_t P_x = {0x09057757, 0xdc5816af, 0x1aa7a09d, 0xe5ba57c4, 0xed6efa3e, 0x3611d5b9, 0xd53fba1e, 0xeb04aae0 };
//     // sm2_uint256_t P_y = {0xee162b93, 0x5a59b146, 0x44c36d8a, 0x5997b1fe, 0x7322c76d, 0x6e45f58e, 0x8392f471, 0xce6fa067 };
//     // sm2_uint256_t Q_x = {0x2e590fdc, 0xb008f54a, 0x838834ed, 0x17b34c81, 0x60f63123, 0x37cec6f8, 0x75d83480, 0xaa307a65 };
//     // sm2_uint256_t Q_y = {0x8fb354e9, 0x54a8c0ee, 0x5622b657, 0xec3c2639, 0xcd4abf81, 0xe6ce7e91, 0x9fe9c933, 0x593293d8 };
//     // sm2_uint256_t R_x = {0xf82c67e5, 0xa4cedea4, 0xdec60ba7, 0x321afd86, 0x0d7a84ad, 0xf0c05a6d, 0x424cc514, 0x3b94d813 };
//     // sm2_uint256_t R_y = {0xbbf4e244, 0x596cd83c, 0x7c67be15, 0x2b2a8810, 0xe9e0e33c, 0x7b5175f8, 0xe4b15ade, 0xa9abc4ac };

//     // 通过
//     // sm2_uint256_t P_x = {0x7fedd43d, 0x4c4e6c14, 0xadd50bdc, 0x32220b3b, 0xc3cc315e, 0x746434eb, 0x1b62eab6, 0x421debd6 };
//     // sm2_uint256_t P_y = {0xe46e09a2, 0xa85841b9, 0xbfa36ea1, 0xe5d7fdfc, 0x153b70c4, 0xd47349d2, 0xcbb42c07, 0x0680512b };
//     // sm2_uint256_t Q_x = {0xc2c19e69, 0x56355d70, 0x9a6d58b5, 0xf14405ff, 0x97b8c8a8, 0x976c436d, 0x98f4548a, 0x126fe19e };
//     // sm2_uint256_t Q_y = {0x7bddcb93, 0x10b532ef, 0x7482ca55, 0xde0b75bf, 0x73030132, 0x12729f64, 0x69cc1072, 0x4bd3a18e };
//     // sm2_uint256_t R_x = {0xbca02da3, 0xaf0abcdb, 0x4c542086, 0xbde1d654, 0xc65a93a5, 0x3df71d54, 0x2dfe192f, 0xb501a951 };
//     // sm2_uint256_t R_y = {0x3b5bc505, 0x7a4f0475, 0xfd099cdc, 0x5bbba878, 0xc793e997, 0x46382a96, 0x0a236d6a, 0x0fd9b783 };

//     // 通过
//     // sm2_uint256_t P_x = {0xfb0d2846, 0x635f35cd, 0xe8a32410, 0x56357d9e, 0xe21fe264, 0x95bb954d, 0xc7fb8848, 0x5e1e24ac };
//     // sm2_uint256_t P_y = {0x305708f4, 0xbdb61bbd, 0x5acc3c56, 0x20d80f7a, 0xf82b0900, 0x1bdd076b, 0x881a8baf, 0x8314d639 };
//     // sm2_uint256_t Q_x = {0xc2c19e69, 0x56355d70, 0x9a6d58b5, 0xf14405ff, 0x97b8c8a8, 0x976c436d, 0x98f4548a, 0x126fe19e };
//     // sm2_uint256_t Q_y = {0x7bddcb93, 0x10b532ef, 0x7482ca55, 0xde0b75bf, 0x73030132, 0x12729f64, 0x69cc1072, 0x4bd3a18e };
//     // sm2_uint256_t R_x = {0x03d489b0, 0x1e484031, 0x180e5314, 0x0ea5a3ad, 0x9c9e2d8c, 0x11497fc7, 0x01c8a855, 0xac931563 };
//     // sm2_uint256_t R_y = {0x4adbad1f, 0xa966a376, 0x133dba7d, 0x4bb39738, 0x7a4b3b9e, 0xc9b322ef, 0xfe3e0803, 0x4cdf59a0 };

//     // 随机通过
//     // sm2_uint256_t P_x = {0x098b0ca7, 0x314516ce, 0xee7b7762, 0x703e3dd1, 0x61917917, 0x37018df4, 0x341ba8cd, 0xef4d67b2 };
//     // sm2_uint256_t P_y = {0xd0b7755a, 0x246a5efe, 0x04a8bb95, 0xdf7f6a82, 0x2516e0b8, 0x2467ee61, 0x48981178, 0xd08c46dd };
//     // sm2_uint256_t Q_x = {0xc386b90c, 0xb4f3589e, 0x1d27c3c6, 0x771a7712, 0xc4c11ce2, 0x40373ce6, 0x80c2ab5a, 0xe51ec24b };
//     // sm2_uint256_t Q_y = {0x96f615c3, 0xb8f0504a, 0xd097e2f2, 0x96035e78, 0x0b24ad4b, 0x68e326b2, 0x62f74dc2, 0x93d88a60 };
//     // sm2_uint256_t R_x = {0x4ef31a71, 0x88f75802, 0xd623c613, 0xaf2fe51d, 0x26ac05e8, 0x9e64f735, 0x9ea8c09a, 0xd3e36299 };
//     // sm2_uint256_t R_y = {0x690b5324, 0xd210879d, 0x39686727, 0x0e54e5a0, 0x949cfba4, 0xa33e97c8, 0x69132abd, 0xe20957c4 };
//     // 随机
//     // sm2_uint256_t P_x = {0x6d3062f4, 0x52435648, 0xc2414a94, 0xbd7d3af1, 0xc135e9c9, 0x008526a4, 0x80fe040b, 0xe6fadd66 };
//     // sm2_uint256_t P_y = {0xce284417, 0x13a3dacf, 0x2360297d, 0x12337f68, 0x0cbc6ec5, 0xda24fb1e, 0x7adb355e, 0xd21b2c6b };
//     // sm2_uint256_t Q_x = {0x7a2ee7a9, 0x3408fe6b, 0xcfe92810, 0x0ce7bb11, 0xd13d02a9, 0x9df31418, 0xeb65bc16, 0xefa577d3 };
//     // sm2_uint256_t Q_y = {0xd937ec32, 0x2e6cc2d7, 0x922074e2, 0xdd498ac1, 0x6b60f4e5, 0xe5b2d0f3, 0xac6ed4c4, 0xdf743e2f };
//     // sm2_uint256_t R_x = {0xaeeea632, 0xf60056c0, 0x69013c6d, 0xd580a659, 0xe36b3d66, 0xc0895eaa, 0x4b17b4dd, 0xe75887b8 };
//     // sm2_uint256_t R_y = {0xce314cb9, 0x501b92f2, 0xdc8e9f26, 0x62ec0c3c, 0x6b599dbe, 0xc1914462, 0x16a35367, 0x021a4f04 };
//     // sm2_uint256_t p_1 = {0};
//     // sm2_copy(p_1, SM2_P);
//     // p_1[0] -= 1;
//     // // _print_256(p_1);
//     // sm2_uint256_t result = {0};
//     // sm2_uint256_t test_inv = {0x1026cd80, 0xc7d6f844, 0x704b7fd9, 0x31775222, 0xa574b7bd, 0x17e554b9, 0xb82e213c, 0x053b878f };
//     // sm2_uint256_t true_inv = {0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };

//     // SM2_Jacobian_Point P, Q, R, tmp, coverted_anwser;
//     // sm2_set_jacobian_point(&P, P_x, P_y);
//     // sm2_set_jacobian_point(&Q, Q_x, Q_y);
//     // sm2_set_jacobian_point(&R, R_x, R_y);
//     // test_point_operation(POINT_IS_ON_CURVE, NULL, &P, NULL, NULL);
//     // test_point_operation(POINT_IS_ON_CURVE, NULL, &Q, NULL, NULL);
//     // test_point_operation(POINT_IS_ON_CURVE, NULL, &R, NULL, NULL);
//     // print_point(&P);
//     // print_point(&Q);
//     // print_point(&R);
//     // sm2_set_zero(P_x);
//     // sm2_jacobian_point_add(&tmp, &P, &Q);
//     // sm2_uint256_t kk = {0};
//     // printf("\ntest P+Q\n");
//     // test_point_operation(POINT_ADD, &R, &P, &Q, kk);

//     // printf("not convert\n");
//     // print_point(&tmp);
//     // // print_point(&P);
//     // // print_point(&Q);
//     // printf("converted\n");
//     // sm2_get_affine_point(&coverted_anwser, &tmp);
//     // print_point(&coverted_anwser);
//     // print_point(&R);
//     // int res = sm2_point_compare(&R, &coverted_anwser);
//     // print_point(&coverted_anwser);
//     // sm2_uint512_t dd = {0x1715edea, 0x1f307cad, 0x997bb31a, 0xcb2738ad, 0xd69e24dc, 0xb9d57c42, 0xfca2ce33, 0xcccaa74a, 0, 0, 0x20d, 0, 0, 0, 0x80, 0};
//     // sm2_uint256_t xx = {0};
//     // SM2_Jacobian_Point tt;
//     // sm2_fast_mod_reduction(xx, dd);
//     // printf("xx:\n");
//     // _print_256(xx);

//     // sm2_uint256_t xx = {0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     // sm2_uint256_t yy = {0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     // sm2_uint256_t sum = {0};
//     // int c = sm2_add(sum, xx, yy);
//     // printf("add c %d\n", c);
//     // _print_256(sum);

//     // sm2_uint256_t G_x = {0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     // sm2_uint256_t G_y = {0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     // sm2_uint256_t G2_x = {0xa3f2bd52, 0x495c2e1d, 0xc08a7331, 0x9c0dfa08, 0xfa73ba4d, 0x0d58ef57, 0xd7c87c00, 0x56cefd60 };
//     // sm2_uint256_t G2_y = {0x970a23c3, 0x6f780d3a, 0x2f6c8e71, 0x6de84c18, 0xf8eaf1bd, 0x68535ce0, 0xcc8189f6, 0x31b7e7e6 }; 
//     // sm2_uint256_t G3_x = {0xd0509ebf, 0xe26918f1, 0x45302244, 0xa13f6bd9, 0xdb41e24c, 0xbe2daa8c, 0xb3c993b4, 0xa97f7cd4 };
//     // sm2_uint256_t G3_y = {0x7458f6e6, 0xaaacdd03, 0xcd045292, 0x7c400ee5, 0x8a72150f, 0xccc5cec0, 0x8c688ef5, 0x530b5dd8 };
//     // sm2_uint256_t neg_G_x = {0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c }; 
//     // sm2_uint256_t neg_G_y = {0xdec60f5f, 0xfd20cd1a, 0x39d5b8c0, 0x2f567882, 0x9496deac, 0xa642311c, 0x0b098863, 0x43c8c95c };
//     // sm2_uint256_t G10_x = {0xdb522756, 0x84a04814, 0xcd219e32, 0xb2d0d065, 0xf65c3e32, 0x21666061, 0x519621c1, 0xd3f94862 };
//     // sm2_uint256_t G10_y = {0xbab82a14, 0x47d46fb2, 0x4d1482d1, 0xf6b743f6, 0x46dca428, 0x2ebd57d1, 0x676f6a74, 0x4b9030cf };
//     // sm2_uint256_t bG_x = {0x4c46c0ba, 0x47f73c32, 0x0c0a127b, 0xd1e9d4a8, 0xcfa1b630, 0x63c06fc4, 0x74a6ebc6, 0x528470bc };
//     // sm2_uint256_t bG_y = {0xabfc1bf4, 0x9d323d4c, 0xc98d2059, 0xe488faae, 0xf6e2c9ce, 0x60962b4c, 0xa15b997e, 0x832cf9c5 };
//     // sm2_uint256_t num_10 = {0x0000000a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
//     // sm2_uint256_t b = {0x4d940e93, 0xddbcbd41, 0x15ab8f92, 0xf39789f5, 0xcf6509a7, 0x4d5a9e4b, 0x9d9f5e34, 0x28e9fa9e };
//     // SM2_Jacobian_Point G_1, G_2, G_3, neg_G, G_10, b_G, P_INF, temp, temp1;
//     // // sm2_set_point_infi(&P_INF);
//     // sm2_set_jacobian_point(&G_1, G_x, G_y);
//     // for(int i=0;i<16;i++){
//     //     sm2_point_double(&temp1, &G_1);
//     //     // sm2_point_copy(&temp, &G_1);
//     //     // sm2_jacobian_point_add(&G_1, &temp, &temp);
//     //     sm2_get_affine_point(&temp, &G_1);
//     //     sm2_point_copy(&G_1, &temp1);
//     //     print_point(&temp);
//     // }
//     // sm2_get_affine_point(&temp, &G_1);
//     // print_point(&temp);
//     // sm2_set_jacobian_point(&G_2, G2_x, G2_y);
//     // sm2_set_jacobian_point(&G_3, G3_x, G3_y);
//     // sm2_set_jacobian_point(&neg_G, neg_G_x, neg_G_y);
//     // sm2_set_jacobian_point(&G_10, G10_x, G10_y);
//     // sm2_set_jacobian_point(&b_G, bG_x, bG_y);
//     // printf("\n\ntest point operation\n");
//     // printf("\ntest G+G\n");
//     // test_point_operation(POINT_ADD, &G_2, &G_1, &G_1, kk); // G + G
//     // printf("test G-G\n");
//     // test_point_operation(POINT_ADD, &P_INF, &G_1, &neg_G, kk); // G - G
//     // printf("test 2G+G\n");
//     // test_point_operation(POINT_ADD, &G_3, &G_2, &G_1, kk); // 2G + G
//     // printf("test 3G-G\n");
//     // test_point_operation(POINT_ADD, &G_2, &G_3, &neg_G, kk); // 3G - G
//     // printf("test [b]G\n");
//     // test_point_operation(POINT_K_MUL, &b_G, &G_1, NULL, b);
//     // printf("test [10]G\n");
//     // test_point_operation(POINT_K_MUL, &G_10, &G_1, NULL, num_10); // [10]G
//     // SM2_Jacobian_Point res={0}, t1;
//     // sm2_point_copy(&res, &G_1);

//     // for(int i=0; i< 65535; ++i){
//     //     sm2_jacobian_point_add(&res, &G_1, &res);
//     // }
//     // // int ret = sm2_point_compare(&res, &G_10);
//     // // printf("10G %d\n", ret);
//     // sm2_get_affine_point(&t1, &res);
//     // print_point(&t1);
//     // print_point(&G_10);
//     // printf("\ntest number operation\n");
//     // test_z256_operation(Z256_INV, test_inv, true_inv, NULL);
//     // test_z256_operation(Z256_NEG, neg_G_y, G_y, NULL);
//     // test_point_operation(POINT_ADD, &G_3, &G_2, &G_1, kk); // 2G + G
//     // test_point_operation(POINT_ADD, &G_3, &G_2, &G_1, -1);
//     // test_point_operation(POINT_ADD, &G_3, &G_2, &G_1, -1);
//     // test_point_operation(POINT_ADD, &G_3, &G_2, &G_1, -1);
//     // printf("%d\n", cc);

//     // sm2_uint256_t lx = {0x09057757, 0xdc5816af, 0x1aa7a09d, 0xe5ba57c4, 0xed6efa3e, 0x3611d5b9, 0xd53fba1e, 0xeb04aae0 };
//     // sm2_uint256_t ly = {0xee162b93, 0x5a59b146, 0x44c36d8a, 0x5997b1fe, 0x7322c76d, 0x6e45f58e, 0x8392f471, 0xce6fa067 };
//     // sm2_uint256_t mx = {0x2e590fdc, 0xb008f54a, 0x838834ed, 0x17b34c81, 0x60f63123, 0x37cec6f8, 0x75d83480, 0xaa307a65 };
//     // sm2_uint256_t my = {0x8fb354e9, 0x54a8c0ee, 0x5622b657, 0xec3c2639, 0xcd4abf81, 0xe6ce7e91, 0x9fe9c933, 0x593293d8 };
//     // sm2_uint256_t rx = {0xf82c67e5, 0xa4cedea4, 0xdec60ba7, 0x321afd86, 0x0d7a84ad, 0xf0c05a6d, 0x424cc514, 0x3b94d813 };
//     // sm2_uint256_t ry = {0xbbf4e244, 0x596cd83c, 0x7c67be15, 0x2b2a8810, 0xe9e0e33c, 0x7b5175f8, 0xe4b15ade, 0xa9abc4ac };
//     // SM2_Jacobian_Point l, m ,r, res, conv;
//     // sm2_set_jacobian_point(&l, lx, ly);
//     // sm2_set_jacobian_point(&m, mx, my);
//     // sm2_set_jacobian_point(&r, rx, ry);
//     // sm2_jacobian_point_add(&res, &l, &m);
//     // sm2_get_affine_point(&conv, &res);
//     // print_point(&conv);
//     SM2_Jacobian_Point P, R;
//     // sm2_uint256_t k = { 0x2f2695da, 0x5b07d971, 0xe37056f4, 0x1c7eba7a, 0x955226ce, 0x671c3d16, 0x7a133a19, 0x00000004 };
//     // sm2_uint256_t P_x = { 0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     // sm2_uint256_t P_y = { 0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     // sm2_uint256_t R_x = { 0xaf8fee2b, 0xb832df3a, 0x2934f5e8, 0xa4c68eb2, 0x4aa7c680, 0x059b34ee, 0x81e59bfc, 0x7c517622 };
//     // sm2_uint256_t R_y = { 0x4d86638f, 0x5a11ac88, 0x7316f287, 0x8aa14979, 0x5f8aa93f, 0x83752875, 0x264bc456, 0x7d409776 };

//     // sm2_uint256_t k = { 0xb180598d, 0x14c37f4a, 0xaeef0a9d, 0xf9b35680, 0x6e465e56, 0x86d791cf, 0xee2b065a, 0x00000005 };
//     // sm2_uint256_t P_x = { 0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     // sm2_uint256_t P_y = { 0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     // sm2_uint256_t R_x = { 0x4ef33cd7, 0x2261fdb8, 0xc724d244, 0xf1cc09a3, 0x3c6b39e0, 0xf10f8cdf, 0x9afbb900, 0x41285619 };
//     // sm2_uint256_t R_y = { 0x5a5e8665, 0xfbc6df58, 0x136a4089, 0x2393c301, 0xe528acd1, 0x51e533a6, 0x27ee8b34, 0xa9dec8d5 };
    
//     // sm2_uint256_t k= { 0x00010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
//     // sm2_uint256_t P_x = { 0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     // sm2_uint256_t P_y = { 0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     // sm2_uint256_t R_x = { 0x7482d023, 0x312d5ca6, 0x90bed320, 0xb3541bd2, 0x2c2b8c73, 0xb118be11, 0x92f69b5b, 0x39d99bbf };
//     // sm2_uint256_t R_y = { 0xcc7cbe33, 0x2b875a20, 0x71487294, 0x7f379746, 0x931d3726, 0x2994db86, 0x271b243c, 0xa9c3cd42 };
//     sm2_uint256_t k = { 0x08dd4d14, 0xfe58cf53, 0xd5a2556c, 0x673e60f1, 0xdd634d77, 0x76103e93, 0x723a12d3, 0x00000005 };
//     sm2_uint256_t P_x = { 0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c };
//     sm2_uint256_t P_y = { 0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2 };
//     sm2_uint256_t R_x = { 0x5e3117e6, 0xeb08e1b1, 0xaaf96a15, 0xc9565855, 0x24225259, 0x452f62f5, 0xe119841c, 0x6ec467fb };
//     sm2_uint256_t R_y = { 0x5b2a9b3b, 0x0cbd3df6, 0xb199516c, 0x5ac056d0, 0x9480aa08, 0xef8492b1, 0xbf058ca9, 0x425a501b };
//     sm2_set_jacobian_point(&P, P_x, P_y);
//     sm2_set_jacobian_point(&R, R_x, R_y);
//     test_point_operation(POINT_K_MUL, &R, &P, NULL, k);
//     return 0;
// }
